#ifndef __PVM_VOICE_SPEEX_H__
#define __PVM_VOICE_SPEEX_H__

#include "pvm/pvmapi.h"
#include "lib/pvmvoice.h"
#include "lib/decoders/speex/pvmspeexincludes.h"

#include "lib/memory/pvmmemory.h"

class PVMVoiceSpeex : public IPVMVoice, public PVMAllocableObject
{
protected:
	static const int MAX_FRAME_SIZE=2000;
	SpeexBits bits;
	ogg_int64_t page_granule;
	ogg_int64_t last_granule;

	int skip_samples;
	int page_nb_packets;
	int speex_serialno;
	spx_int32_t frame_size;
	int granule_frame_size;
	int nframes;
	int extra_headers;
	int packet_count;
	spx_int32_t enh_enabled;
	spx_int32_t rate;
	int forceMode;
	int channels;
	void* st;
	int lookahead;
	int packet_no;
	pvm_bool stream_init;
	int samples_decoded;
	
	ogg_sync_state oy;
	ogg_page       og;
	ogg_packet     op;
	ogg_stream_state os;
	SpeexStereoState stereo;

	pvm_int16*	outBuffer;
	pvm_int		outBufferSize;
	pvm_int		samples_copied;

	IPvmInStream* stream;
	pvm_bool isInitialized;
	pvm_bool closeStream;

	pvm_bool decodeError;
	pvm_bool paused;
	pvm_int32 loopCount;

	pvm_int64 loopStart;
	pvm_int64 loopEnd;

	pvm_bool* streamIsUsed;
	bool firstDecode;


	pvm_bool eos;
	int j;
	short output[MAX_FRAME_SIZE];
	int frame_offset;
	int new_frame_size;
protected:
	PVMVoiceSpeex();
	pvm_bool Init(IPvmInStream* stream, pvm_bool closeStream);
	pvm_uint32 decodeDataBlock();
	pvm_uint32 copyDecodedData(void* buffer, pvm_int maxSamplesNum);
public:
	virtual ~PVMVoiceSpeex();

	virtual void GetFormat(pvm_uint32 &samplesPerSecond, pvm_uint32 &bitsperSample, pvm_uint32 &chanels);
	virtual pvm_uint32 GetSamplesPerSecond();
	virtual pvm_uint32 GetBitsPerSample();
	virtual pvm_uint32 GetChanelsNum();

	virtual pvm_uint32 FillBuffer(void *buffer, pvm_uint32 numSamples);
	virtual void SetPause(pvm_bool pause);
	virtual pvm_bool GetPause();
	virtual pvm_bool IsAlive();
	virtual void DoDestroy();

	virtual void OnIdle();

	virtual void SetLoopCount(pvm_int32 loopCount);
	virtual pvm_int32 GetLoopCount();
	virtual pvm_bool SetLoopInSamples(pvm_int64 /*loopFrom*/, pvm_int64 /*loopTo*/) { return false; }
	virtual pvm_bool GetLoopInSamples(pvm_int64& /*loopFrom*/, pvm_int64& /*loopTo*/) { return false; }
	virtual pvm_bool GetLoopInMS(pvm_int32& /*loopFrom*/, pvm_int32& /*loopTo*/) { return false; }

	virtual pvm_bool SetPositionMS(pvm_int32 position);
	virtual pvm_int32 GetPositionMS();

	virtual pvm_bool GetOption(const pvm_char* optionName, void* optionVal, pvm_uint32* optionSize);
	virtual pvm_bool SetOption(const pvm_char* optionName, void* optionVal, pvm_uint32 optionSize);

	static PVMVoiceSpeex* Create(IPvmInStream* srcStream, pvm_bool copyStream, pvm_bool* streamIsUsed);
	static void *process_header(ogg_packet *op, spx_int32_t enh_enabled, spx_int32_t *frame_size, int *granule_frame_size, spx_int32_t *rate, int *nframes, int forceMode, int *channels, SpeexStereoState *stereo, int *extra_headers);
};


#endif
